package de.koller.magnitude.prototype;

import de.koller.magnitude.web.WebDisplayRoot;
import de.koller.magnitude.web.pages.MPage;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Random;

public class WinPage extends MPage {

	public static final Random RND = new Random();
	
	private String log = "";
	
	public WinPage( WebDisplayRoot root ) {
		super( root );
	}
	
	public void calc() {
		log = "";
		log += "<h1>Match-Prototype</h1>";
		
		int pn = 18;
		Player[] player = new Player[ pn ];
		for( int i = 0; i < pn; i++ )
			player[i] = new Player( i );
		
		List<Match> matches = makeMatches( player );
		List<GameDay> gamedays = makeGameDays( matches );
		
		log += "<h2>Spielplan</h2>";
		for( Player p : player )
			printGameplan( gamedays, p );
		
		for( int i = 0; i < gamedays.size(); i++ ) {
			GameDay g = gamedays.get( i );
			log += "<h2>Spieltag " + (i+1) + "</h2>";
			g.play();
			
			log += "<h3>Ergebnis nach " + (i+1) + " von " + gamedays.size() + " Spieltagen</h3>";
			printResult( player );
		}
	}
	
	private void printResult( Player[] player ) {
		List<Player> p = Arrays.asList( player );
		Collections.sort( p, new Comparator<Player>() {
			@Override public int compare( Player o1, Player o2 ) {
				return -Integer.compare( o1.cash, o2.cash );
			}
		} );
		
		String[][] t = new String[4][p.size()+1];
		t[0][0] = "<b>Platz</b>";
		t[1][0] = "<b>Spieler</b>";
		t[2][0] = "<b>Punkte</b>";
		t[3][0] = "<b></b>";
		
		for( int i = 0; i < p.size(); i++ ) {
			t[0][i+1] = (i+1) + ".";
			t[1][i+1] = p.get( i ).toString();
			t[2][i+1] = p.get( i ).cash + "";
			
			int plc = p.get( i ).place - (i+1);
			
			if( plc == 0 ) {
				t[3][i+1] = "";
				continue;
			} else
				t[3][i+1] = (plc > 0 ? "+" : "") + plc;
			p.get( i ).place = i+1;
		}
		log += table( t, 1 );
	}
	
	private void printGameplan( List<GameDay> gamedays, Player p ) {
		log += "<h3>Spielplan für " + p.toString() + "</h3>";
		String[][] t = new String[2][gamedays.size()];
		
		for( int i = 0; i < gamedays.size(); i++ ) {
			t[0][i] = (i+1) + ". Spieltag";
			
			Match m = gamedays.get( i ).getMatch( p );
			if( m == null )
				t[1][i] = "Frei";
			else if( m.player1 == p )
				t[1][i] = "Gegen " + m.player2.toString();
			else
				t[1][i] = "Gegen " + m.player1.toString();
		}
		
		log += table( t, 1 );
	}
	
	private List<GameDay> makeGameDays( List<Match> matches ) {
		Collections.shuffle( matches, RND );
		List<GameDay> gd = new ArrayList<>();
		
		while( !matches.isEmpty() ) {
			GameDay d = new GameDay();
			
			List<Match> rm = new ArrayList<>();
			for( Match m : matches ) {
				if( d.isFree( m.player1 ) && d.isFree( m.player2 ) ) {
					rm.add( m );
					d.matches.add( m );
				}
			}
			
			gd.add( d ); 
			matches.removeAll( rm );
		}
		
		return gd;
	}
	
	private List<Match> makeMatches( Player[] player ) {
		List<Match> ms = new ArrayList<>();
		
		for( int i = 0; i < player.length; i++ )
			for( int j = 0; j < player.length; j++ ) {
				if( i == j )
					continue;
				
				Player p1 = player[i];
				Player p2 = player[j];
				if( !isMatchValid( ms, p1, p2 ) )
					continue;
				
				Match m = new Match( p1, p2 );
				ms.add( m );
			}
		
		return ms;
	}
	
	private boolean isMatchValid( List<Match> matches, Player p1, Player p2 ) {
		for( Match m : matches ) {
			if( m.player1 == p1 && m.player2 == p2 ) return false;
			if( m.player1 == p2 && m.player2 == p1 ) return false;
		}
		
		return true;
	}

	@Override
	protected String getBody() {
		calc();
		return log;
	}
	
	@Override
	protected String getPageTitle() {
		return "Prototype";
	}
	
	private class Player {
		private final int id;
		private int cash = 100;
		private int place = 0;

		public Player( int id ) {
			this.id = id;
		}

		@Override
		public String toString() {
			return "Spieler " + id;
		}
		
	}
	
	private class GameDay {
		private final List<Match> matches = new ArrayList<>();
		
		private boolean isFree( Player p ) {
			for( Match m : matches )
				if( m.player1 == p || m.player2 == p )
					return false;
			return true;
		}
	
		private Match getMatch( Player p ) {
			for( Match m : matches )
				if( m.player1 == p || m.player2 == p )
					return m;
			return null;
		}
		
		public void play() {
			String[][] r = new String[3][ matches.size()+1 ];
			r[0][0] = "<b>Spiel</b>";
			r[1][0] = "<b>Ergebnis</b>";
			r[2][0] = "<b>Punkte</b>";
			
			for( int i = 0; i < matches.size(); i++ ) {
				String[] mr = matches.get( i ).play();
				for( int j = 0; j < mr.length; j++ )
					r[j][i+1] = mr[j];
			}
			
			log += table( r, 1 );
		}
	}
	
	private class Match {
		private final Player player1;
		private final Player player2;

		public Match( Player player1, Player player2 ) {
			this.player1 = player1;
			this.player2 = player2;
		}

		public String[] play() {
			String[] r = new String[3];
			int c = Math.min( player1.cash, player2.cash );
			r[0] = player1.toString() + " vs. " + player2.toString() + " um " + c;
			
			int w1 = RND.nextInt( c+1 );
			int w2 = RND.nextInt( c+1 );
			
			r[1] = player1.toString() + ": " + w1 + " / " +	player2.toString() + ": " + w2;
	
			int wc = Math.max( w1, w2 ) - Math.min( w1, w2 );
			int p1wc = w1 > w2 ? wc : -wc; 
			int p2wc = w2 > w1 ? wc : -wc; 
			
			player1.cash += p1wc;
			player2.cash += p2wc;
			r[2] = player1.toString() + ": " + player1.cash + " (" + p1wc + ")"
					+ " / " + 
				player2.toString() + ": " + player2.cash + " (" + p2wc + ")";
			return r;
		}
	}
	
}
